﻿using Platform.Data.Entities.MySql;
using Microsoft.EntityFrameworkCore;
using MiniFox.Components;
using MiniFox.Data;
using MiniFox.Platform;
using MiniFox.Platform.Applications.Auth;
using System.Data;
using MiniFox.Utility;
using System.Runtime.InteropServices;
using System.Threading;
using Newtonsoft.Json;

namespace DataService.Data
{
    /// <summary>
    /// 
    /// </summary>
    [AutoResolve]
    public class ServiceDataSourceFactory : DataSourceFactory<IAuthStateManagement>
    {
        const string REPO_NAME = "dmc";
        PlatformDbContext _context;

        public ServiceDataSourceFactory(IAuthStateManagement openAuthState) : this(openAuthState, new PlatformDbContext(new DbContextOptions<PlatformDbContext>()))
        {

        }
        public ServiceDataSourceFactory(IAuthStateManagement openAuthState, PlatformDbContext context) : base(openAuthState)
        {
            _context = context;
        }

        public PlatformDbContext Context
        {
            get
            {
                return _context;
            }
        }

        private VersionItem GetPublishCommand(string name)
        {
            var versionSet = this.Context.VersionSet.SingleOrDefault(v => v.RepoName == REPO_NAME && v.Name == name);
            if (versionSet == null || versionSet.PubId == null)
            {
                return null;
            }

            var publish = this.Context.PublishLog.SingleOrDefault(p => p.Id == versionSet.PubId);
            if (publish == null)
            {
                return null;
            }
            VersionItem command = this.Context.VersionItem.SingleOrDefault(c => c.Id == publish.VersionId);
            return command;
        }

        //protected virtual void MappingCommand(IDataCommand dataCommand, VersionItem versionItem)
        //{
        //    if (dataCommand == null)
        //        return;
        //    dynamic command = versionItem.Content.ToJsonObject();
        //    dataCommand.TimeOut = command.TimeOut;
        //    dataCommand.Preparable = false;

        //    //if (dataCommand.Parameters == null || dataCommand.Parameters.Count <= 0)
        //    //    return;
        //    var parameters = command.Parameters;
        //    foreach (dynamic par in parameters)
        //    {
        //        Parameter p = new Parameter(par.Name) { ParameterName = par.ParameterName, ClrType = Type.GetType(par.Type), Nullable = par.Nullable, Direction = Enum.Parse<ParameterDirection>(par.Direction), DefaultValue = par.DefaultValue };
        //        p.Precision = par.Precision;
        //        p.Scale = par.Scale;
        //        p.Size = par.Size;
        //        dataCommand.Parameters.Add(p);
        //    }
        //}

        protected override Database CreateDatabase(string connectionName)
        {
            var connSetting = this.Context.DsConnection.SingleOrDefault(c => c.Name == connectionName);
            if (connSetting == null)
            {
                return base.CreateDatabase(connectionName);
            }
            return Database.CreateDatabase(connSetting.ConnectionString, connSetting.ProviderName);
        }

        public override IDataCommand GetDataCommand(string name)
        {
            var versionItem = GetPublishCommand(name);
            if (versionItem == null)
            {
                return base.GetDataCommand(name);
            }
            Command command = versionItem.Content.ToJsonObject<Command>();

            var dataCommand = this.CreateDataCommand(name, command.Text, Enum.Parse<CommandType>(command.CommandType), command.ConnectionName);
            dataCommand.TimeOut = command.TimeOut;
            dataCommand.Preparable = false;

            var parameters = command.Parameters;
            foreach (CommandParameter par in parameters)
            {
                Parameter p = new Parameter(par.Name) { ParameterName = par.ParameterName, ClrType = Type.GetType(par.Type), Nullable = par.Nullable, Direction = Enum.Parse<ParameterDirection>(par.Direction), DefaultValue = par.DefaultValue };
                p.Precision = par.Precision;
                p.Scale = par.Scale;
                p.Size = par.Size;
                dataCommand.Parameters.Add(p);
            }
            return dataCommand;
        }

        protected  struct Command
        {
            [JsonProperty("name")]
            public string Name { get;  set; }

            [JsonProperty("text")]
            public string Text { get;  set; }

            [JsonProperty("connectionName")]
            public dynamic ConnectionName { get;  set; }

            [JsonProperty("commandType")]
            public string CommandType { get;  set; }

            [JsonProperty("timeout")]
            public int TimeOut { get;  set; }

            [JsonProperty("parameters")]
            public CommandParameter[] Parameters { get;  set; }
        }

        protected  struct CommandParameter
        {
            [JsonProperty("name")]
            public string Name { get;  set; }

            [JsonProperty("parameterName")]
            public string ParameterName { get;  set; }

            [JsonProperty("type")]
            public string Type { get;  set; }

            [JsonProperty("nullable")]
            public bool Nullable { get;  set; }

            [JsonProperty("direction")]
            public string Direction { get;  set; }

            [JsonProperty("defaultValue")]
            public string DefaultValue { get;  set; }

            [JsonProperty("precision")]
            public byte Precision { get;  set; }

            [JsonProperty("scale")]
            public byte Scale { get;  set; }

            [JsonProperty("size")]
            public int Size { get;  set; }
        }
    }

}
